1   /*
2    * Copyright (C) 2011 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.cache;
18  
19  import com.google.common.collect.ImmutableList;
20  import com.google.common.collect.ImmutableMap;
21  import com.google.common.collect.Lists;
22  import com.google.common.util.concurrent.Futures;
23  import com.google.common.util.concurrent.ListenableFuture;
24  
25  import junit.framework.TestCase;
26  
27  import java.util.LinkedList;
28  import java.util.Map;
29  import java.util.concurrent.Executor;
30  import java.util.concurrent.atomic.AtomicInteger;
31  
32  /**
33   * Unit tests for {@link CacheLoader}.
34   *
35   * @author Charles Fry
36   */
37  public class CacheLoaderTest extends TestCase {
38  
39    private static class QueuingExecutor implements Executor {
40      private LinkedList<Runnable> tasks = Lists.newLinkedList();
41  
42      @Override
43      public void execute(Runnable task) {
44        tasks.add(task);
45      }
46  
47      private void runNext() {
48        tasks.removeFirst().run();
49      }
50    }
51  
52    public void testAsyncReload() throws Exception {
53      final AtomicInteger loadCount = new AtomicInteger();
54      final AtomicInteger reloadCount = new AtomicInteger();
55      final AtomicInteger loadAllCount = new AtomicInteger();
56  
57      CacheLoader<Object, Object> baseLoader = new CacheLoader<Object, Object>() {
58        @Override
59        public Object load(Object key) {
60          loadCount.incrementAndGet();
61          return new Object();
62        }
63  
64        @Override
65        public ListenableFuture<Object> reload(Object key, Object oldValue) {
66          reloadCount.incrementAndGet();
67          return Futures.immediateFuture(new Object());
68        }
69  
70        @Override
71        public Map<Object, Object> loadAll(Iterable<? extends Object> keys) {
72          loadAllCount.incrementAndGet();
73          return ImmutableMap.of();
74        }
75      };
76  
77      assertEquals(0, loadCount.get());
78      assertEquals(0, reloadCount.get());
79      assertEquals(0, loadAllCount.get());
80  
81      baseLoader.load(new Object());
82      baseLoader.reload(new Object(), new Object());
83      baseLoader.loadAll(ImmutableList.of(new Object()));
84      assertEquals(1, loadCount.get());
85      assertEquals(1, reloadCount.get());
86      assertEquals(1, loadAllCount.get());
87  
88      QueuingExecutor executor = new QueuingExecutor();
89      CacheLoader<Object, Object> asyncReloader =
90          CacheLoader.asyncReloading(baseLoader, executor);
91  
92      asyncReloader.load(new Object());
93      asyncReloader.reload(new Object(), new Object());
94      asyncReloader.loadAll(ImmutableList.of(new Object()));
95      assertEquals(2, loadCount.get());
96      assertEquals(1, reloadCount.get());
97      assertEquals(2, loadAllCount.get());
98  
99      executor.runNext();
100     assertEquals(2, loadCount.get());
101     assertEquals(2, reloadCount.get());
102     assertEquals(2, loadAllCount.get());
103   }
104 }